package com.logic.landseaserver.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.logic.landseaserver.domain.*;
import com.logic.landseaserver.persistence.read.CustomerCardReadMapper;
import com.logic.landseaserver.persistence.write.CustomerCardWriteMapper;
import com.logic.landseaserver.service.*;
import com.logic.landseaserver.ws.dto.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.logic.common.domain.Code;
import com.logic.common.exception.BusinessException;
import com.logic.common.security.SecurityUtils;
import com.logic.common.util.QueryUtil;
import com.logic.common.util.SysUtil;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.VariableChar;
import com.logic.landseaserver.common.config.SendMsgConfiguration;
import com.logic.landseaserver.common.enums.BillTypeEnum;
import com.logic.landseaserver.common.enums.LeaseCodeEnum;
import com.logic.landseaserver.common.enums.PaymentModelCodeEnum;
import com.logic.landseaserver.common.enums.ProjectStatusCodeEnum;
import com.logic.landseaserver.common.enums.RoomStatusCodeEnum;
import com.logic.landseaserver.common.enums.UserTypeEnum;
import com.logic.landseaserver.common.exception.LandseaBusinessException;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.util.LandSeaUtil;
import com.logic.landseaserver.common.util.SMSUtil;
import com.logic.landseaserver.models.authcode.bean.UsedAuthCode;
import com.logic.landseaserver.models.authcode.service.CouponUsedService;
import com.logic.landseaserver.models.changeroom.service.ChangeRoomContractService;
import com.logic.landseaserver.models.independent.service.BillIndependentService;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.persistence.read.DepositReadMapper;
import com.logic.landseaserver.persistence.read.UrgentReadMapper;
import com.logic.landseaserver.persistence.write.ContractWriteMapper;
import com.logic.landseaserver.persistence.write.RoomWriteMapper;
import com.logic.landseaserver.persistence.write.UrgentWriteMapper;
import com.logic.landseaserver.ws.request.ContractUser;
import com.logic.landseaserver.ws.request.CreateContractUrgentReq;
import com.logic.landseaserver.ws.request.CreateOffLineContractsReq;
import com.logic.landseaserver.ws.request.RoomDetailReq;
import com.logic.landseaserver.ws.request.UpdateOffLineContractsReq;
import com.logic.system.domain.Configuration;
import com.logic.system.domain.User;
import com.logic.system.service.ICodeService;
import com.logic.system.service.IConfigurationService;
import com.logic.system.service.impl.ConfigurationService;

@Service
public class ContractOfflineServiceImpl implements IContractOfflineService {

    @Autowired
    private IUser userService;
    @Autowired
    private ICustomer customerService;
    @Autowired
    private ContractReadMapper contractReadMapper;

    @Autowired
    private BillIndependentService billIndependentService;
    
    @Autowired
    private IProjectAppartment roomService;
    @Autowired
    private RoomWriteMapper roomWriteMapper;
    @Autowired
    private ContractWriteMapper contractWriteMapper;

    @Autowired
    private IConfigurationService configService;

    @Autowired
    private UrgentWriteMapper urgentWriteMapper;

    @Autowired
    private IBillService billService;

    @Autowired
    private IProjectAppartment projectAppartmentService;

    @Autowired
    private UrgentReadMapper urgentReadMapper;

    @Autowired
    private DepositReadMapper depositReadMapper;

    @Autowired
    private IContractService contractService;

    @Autowired
    private ICodeService codeService;

    @Autowired
    private SendMsgConfiguration sendMsgConfiguration;

    @Autowired
    private CouponUsedService couponUsedService;

    @Autowired
    private IConfigurationService configurationService;
    
    @Autowired
    private ChangeRoomContractService changeRoomContractService;

    @Autowired
    private CustomerCardReadMapper customerCardReadMapper;

    @Autowired
    private CustomerCardWriteMapper customerCardWriteMapper;

    @Autowired
    private ICustomerCardService customerCardService;

    private static final Logger LOG = LoggerFactory.getLogger(ContractOfflineServiceImpl.class);

    /**
     * 事务已添加
     */
    @Override
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = {BusinessException.class,
            LandseaBusinessException.class, Exception.class})
    public int insert(Object o)
            throws BusinessException, LandseaBusinessException {

        CreateOffLineContractsReq objCts = (CreateOffLineContractsReq) o;
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        validateForInsert(o);

        Integer userId = objCts.getUserId();
        //获取当前用户版本
        String version = checkUserInfo(objCts);


        // 判断此房间是否再有效合同内
        Integer counts = contractReadMapper.queryApartContractCounts(objCts.getRoomId());
        if (counts >= 1) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_CONTRACT_APRT_ISRENT);
        }
        // 判断名下是否有未处理的合同 状态为新建
       /*   List<Contract> noDelContracts =
                contractReadMapper.queryContractByStatus(ContractStatusCodeEnum.NEW.getCode(), userId);
        if (noDelContracts.size() > 0) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_CONTRACT_NO_PAY);
        }*/

        // 判断名下是否存在有效合同
        /*List<Contract> onlineContracts =
                contractReadMapper.queryContractByStatus(ContractStatusCodeEnum.SIGN.getCode(), userId);
        if (onlineContracts.size() > 0) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_CONTRACT_IS_ONLINE);
        }*/

        RoomDetailReq aprt = roomService.searchRoomInfo(objCts.getRoomId());
        if (aprt == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_APRT_ISNULL);
        }
        checkStatus(aprt, objCts);
        calculationMonthRent(aprt, objCts, null);

        // 新建合同
        Contract ctc = CreateOffLineContractsReq.convertDTOtoContract(objCts);
        ctc.setUserId(userId);
        // 房间信息
        ctc.setProjectId(aprt.getPrjId());
      //  ctc.setPropertyFee(BigDecimal.valueOf(aprt.getPropertyFee()).doubleValue());
        ctc.setOffLine(true);
        ctc.setUserVersion(version);
        ctc.setOriginalWaterDeposit(aprt.getProject().getDepositWater());
        ctc.updateCommonInfo(systemId);

        // 查看是否有定金
        HashMap depositMap = new HashMap();
        depositMap.put("prjId", aprt.getPrjId());
        depositMap.put("cellPhone", objCts.getCellPhone());
        depositMap.put("idNo", objCts.getCertificatesId());
        List<Deposit> depositList = depositReadMapper.queryUnusedDeposit(depositMap);
        Deposit deposit = null;
        if (objCts.getDepositId() != null) {
            for (Deposit ds : depositList) {
                LOG.info("符合条件的定金编号为：" + ds.getId() + "  " + ds.getUserId());
                if (objCts.getDepositId().equals(ds.getId())) {
                    deposit = ds;
                    ctc.setDepositId(ds.getId());
                    break;
                }
            }
        }

        //查看是否有授权码
        couponUsedService.checkUesdAuthCode(LandeaConstants.QueryUesdCodeType.CONTRACT,userId,objCts.getAuthCodes());

        // 设置收取滞纳金、门锁时长
        Integer lateFeeDay = configurationService.getIntegerValue("SYS_TIM_FOR_LAT_FEE");
        Integer payLastDay = configurationService.getIntegerValue("PAY_LAST_DAY_TIME");
        ctc.setLatefeeDay(lateFeeDay);
        ctc.setLastPayDay(payLastDay);
        
        contractWriteMapper.insertSelective(ctc);
        if (ctc.getId() != null) {
            // 添加联系人信息
            if (objCts.getUrgentDTO() != null) {
                Urgent urgent = UrgentDTO.fromDTOtoUrgent(objCts.getUrgentDTO());
                urgent.setContractId(ctc.getId());
                urgent.updateCommonInfo(systemId);
                urgentWriteMapper.insertSelective(urgent);
            }
            //添加银行卡信息
            if(objCts.getCardUserName()!=null){
                CustomerCard customerCard =CreateOffLineContractsReq.convertDTOtoCustomerCard(objCts);
                customerCard.setSourceId(ctc.getId());
                customerCard.updateCommonInfo(systemId);
                customerCardWriteMapper.insertSelective(customerCard);
            }
            // 如果有定金，则需判断预定转签约时 是否有换房操作，如有，则需将预定房间改为空置状态
            if (deposit != null) {
                if (!deposit.getRoomId().equals(ctc.getRoomId())) {
                    // 修改房间状态
                    Room dsRoom = new Room();
                    dsRoom.setId(deposit.getRoomId());
                    dsRoom.setAppendStatus(RoomStatusCodeEnum.LRB1.getCode());
                    projectAppartmentService.updateAppendStatus(dsRoom);
                }
            }

            // 检查是否有跨店换房申请记录，如果有，则关联当前合同
            changeRoomContractService.processChangeRoomContract(ctc);
            
            // 设置为已签约
            Room room = new Room();
            room.setId(objCts.getRoomId());
            room.setSigned(true);
            room.updateCommonInfo(systemId);
            roomWriteMapper.updateByPrimaryKeySelective(room);

            try {
                billService.createFirstBill(ctc.getId(),objCts.getAuthCodes());
                // 生成pdf
                contractService.createPdf(ctc.getId());
            } catch (LandseaException e) {
                LOG.error("重新生成pdf异常", e);
                throw new LandseaBusinessException(e.getErrorEnum());
            } catch (Exception e) {
                LOG.error("重新生成pdf异常", e);
            }
        }
        return ctc.getId();
    }


    private String checkUserInfo(CreateOffLineContractsReq dto) throws LandseaBusinessException {
        CustomerVersion  customer = customerService.getNewVersion(dto.getUserId());

        if(!dto.getCellPhone().equals(customer.getPhone())){
            throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.DEPOSIT_PARAM_IS_ERROR.getDesc(), VariableChar.PHONE));
        }

        if(!dto.getCertificatesName().equals(customer.getName())){
            throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.DEPOSIT_PARAM_IS_ERROR.getDesc(),VariableChar.NAME));
        }

        if(!dto.getGender().equals(customer.getGender())){
            throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.DEPOSIT_PARAM_IS_ERROR.getDesc(),VariableChar.GENDER));
        }

        if(!dto.getCertificatesType().equals(customer.getCertificatesType())){
            throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.DEPOSIT_PARAM_IS_ERROR.getDesc(),VariableChar.CERTIFICATESTYPE));
        }

        if(!dto.getCertificatesType().equals(customer.getCertificatesType())){
            throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.DEPOSIT_PARAM_IS_ERROR.getDesc(),VariableChar.CERTIFICATESNO));
        }

        if(!dto.getCertificatesAddress().equals(customer.getCertificatesAddress())){
            throw new LandseaBusinessException(String.format(LandseaErrorMessageEnum.DEPOSIT_PARAM_IS_ERROR.getDesc(),VariableChar.CERTIFICATESADDRESS));
        }


        return  customer.getVersionNumber();

    }
    private void checkStatus(RoomDetailReq aprt, CreateOffLineContractsReq objCts)
            throws LandseaBusinessException {

        ProjectDetailDTO project = aprt.getProject();
        if (project == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_ISNULL);
        }

        if (!project.getStatus().equals(ProjectStatusCodeEnum.LPA2.getCode())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_IS_LPA2);
        }

        if (!aprt.getStatus().equals(RoomStatusCodeEnum.LRA2.getCode())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOM_IS_LPA2);
        }
        if (!aprt.getAppendStatus().equals(RoomStatusCodeEnum.LRB1.getCode())
                && !aprt.getAppendStatus().equals(RoomStatusCodeEnum.LRB2.getCode())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOM_IS_LPB1);
        }

        // 判断是否支持此付租方式
        List<String> list = Arrays.asList(project.getPaymentMode().split(","));
        if (!list.contains(objCts.getPaymentMode())) {
            throw new LandseaBusinessException(
                    LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_HAS_NO_PAYMENTHOD_MODEL);
        }
        // 判断是否支持此租期
        List<String> list2 = Arrays.asList(project.getLease().split(","));
        if (!list2.contains(objCts.getLease())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_HAS_NO_LEASE);
        }

    }

    @Override
    public void calculationMonthRent(RoomDetailReq aprt, CreateOffLineContractsReq objCts, Integer changeRoomMonth) {
        //租期
        Integer month = 0;
        if(!objCts.getLease().equals(LeaseCodeEnum.LEAS99.getCode())){
            month = LeaseCodeEnum.getMonth(objCts.getLease());
            objCts.setLeaseM(month);
            objCts.setLeaseD(0);
        }else{
            month = objCts.getLeaseM();
        }
        Double priceHourse = aprt.getRent();
        Double waterDeposit= aprt.getProject().getDepositWater();
        double discountUp = 1;
        // 换房要特殊处理
        if (null != changeRoomMonth) 
        {
            if (changeRoomMonth < 6)
            {
                Configuration config = configService.get("SYS_LEASE_PRICE_RISE");
                if (config != null) {
                    discountUp += Double.valueOf(config.getValue());
                }
            }
        }
        else
        {
            if ( month < 6) {
                Configuration config = configService.get("SYS_LEASE_PRICE_RISE");
                if (config != null) {
                    discountUp += Double.valueOf(config.getValue());
                }
            }
        }
        // 转租特殊处理
        if (aprt.getOprType() != null && aprt.getOprType().equals(LandeaConstants.ReRentType.CHANGE)){
            priceHourse = priceHourse*1;
        }else{
            priceHourse = priceHourse * discountUp;
        }
        objCts.setPrice(LandSeaUtil.getIntDouble(aprt.getRent()*discountUp));
        Double propertyFee= aprt.getPropertyFee();
        // 押金基数
        Integer depositBase = PaymentModelCodeEnum.getDepositMonth(objCts.getPaymentMode());
        /*if (depositBase == null){
            throw LandseaException.createException(
                    LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECT_HAS_NO_PAYMENTHOD_MODEL);
        }*/
        Double depositPrice = LandSeaUtil.getIntDouble(priceHourse)*depositBase;
        if(objCts.getAuthCodes()!=null){
            //获取按月优惠折扣的授权码
            List<UsedAuthCode> discountCodes = objCts.getAuthCodes().stream().filter(e-> e.getOfferType().equals(LandeaConstants.OfferType.BYMONTH) &&
                e.getMoneyType().equals(LandeaConstants.MoneyType.DISCOUNT)
                   // && e.getCouponUesdId()==null
                    && !e.getAuthFee().equals(BillTypeEnum.CTBI11.getCode())).collect(Collectors.toList());
            if(discountCodes.size()!=0){
                for(UsedAuthCode dcode:discountCodes){
                    //月租金
                    if(dcode.getAuthFee().equals(BillTypeEnum.CTBI8.getCode())){
                        priceHourse = priceHourse*dcode.getQuota();
                    } else if(dcode.getAuthFee().equals(BillTypeEnum.CTBI11.getCode())){//押金
                       // depositPrice = depositPrice*dcode.getQuota();
                    }else if(dcode.getAuthFee().equals(BillTypeEnum.CTBI9.getCode())){//服务费
                        propertyFee =propertyFee*dcode.getQuota();
                    }
                }
            }
            //获取按月优惠折扣的授权码
            List<UsedAuthCode> moneyCodes = objCts.getAuthCodes().stream().filter(e-> e.getOfferType().equals(LandeaConstants.OfferType.BYMONTH) &&
                    e.getMoneyType().equals(LandeaConstants.MoneyType.MONEY)
                   // && e.getCouponUesdId()==null
                    && !e.getAuthFee().equals(BillTypeEnum.CTBI11.getCode())).collect(Collectors.toList());
            if(moneyCodes.size()!=0){
                Set<String> authTypeSet = new HashSet<>();
                moneyCodes.forEach(e->authTypeSet.add(e.getAuthFee()));
                for(String authType : authTypeSet){
                    List<UsedAuthCode> feeAuthCodes = moneyCodes.stream().filter(e -> e.getAuthFee().equals(authType)).collect(Collectors.toList());
                    Double authTypeAmout=0.0;
                    if(feeAuthCodes.size()!=0){
                        for(UsedAuthCode uac : feeAuthCodes){
                            authTypeAmout = authTypeAmout +uac.getQuota();
                        }
                    }
                    //月租金
                    if(authType.equals(BillTypeEnum.CTBI8.getCode())){
                        priceHourse = priceHourse-authTypeAmout;
                    } else if(authType.equals(BillTypeEnum.CTBI11.getCode())){//押金
                    //    depositPrice = depositPrice-authTypeAmout;
                    }else if(authType.equals(BillTypeEnum.CTBI9.getCode())){//服务费
                        propertyFee = propertyFee-authTypeAmout;
                    }
                }
            }
            priceHourse =  LandSeaUtil.getIntDouble(priceHourse);
            depositPrice=priceHourse*depositBase;   //押金=减免后月租金
            //获取押金的按次优惠
            List<UsedAuthCode> authDepositCode = objCts.getAuthCodes().stream().filter(e-> e.getOfferType().equals(LandeaConstants.OfferType.BYSINGLE) &&
                    e.getAuthFee().equals(BillTypeEnum.CTBI11.getCode())).collect(Collectors.toList());
                    //&& e.getCouponUesdId()==null
            if(authDepositCode.size()!=0){
                Double authMoney = 0.0;
                for (UsedAuthCode code : authDepositCode)
                {
                    //折扣类 有且只有一个
                    if(code.getMoneyType().equals(LandeaConstants.MoneyType.DISCOUNT)){
                        depositPrice = depositPrice*code.getQuota();
                    }else{
                        Double uesdMoney = LandSeaUtil.get2Double(depositPrice - authMoney);// 此次最多允许使用的优惠金额
                        Double crtAuthMoney = code.getQuota();// 此次优惠金额
                        if (authMoney.compareTo(depositPrice) < 0)
                        {// 如果优惠金额<费项金额 才允许使用授权码
                            Double realAuthMoney = 0.0;
                            if (crtAuthMoney.compareTo(uesdMoney) >= 0)
                            {// 如果当前优惠金额大于等于费项金额允许使用此次最大优惠金额
                                realAuthMoney = uesdMoney;
                                code.setQuota(realAuthMoney);
                            } else{
                                realAuthMoney = crtAuthMoney;
                            }
                            depositPrice = depositPrice-realAuthMoney;
                        }
                    }
                }
            }
            //获取水费押金的按次优惠
            List<UsedAuthCode> authWaterDepositCode = objCts.getAuthCodes().stream().filter(e-> e.getOfferType().equals(LandeaConstants.OfferType.BYSINGLE) &&
                    e.getAuthFee().equals(BillTypeEnum.CTBI10.getCode())).collect(Collectors.toList()); //&& e.getCouponUesdId()==null
            if(authWaterDepositCode.size()!=0){
                Double authWMoney = 0.0;
                for (UsedAuthCode code : authWaterDepositCode)
                {
                    //折扣类 有且只有一个
                    if(code.getMoneyType().equals(LandeaConstants.MoneyType.DISCOUNT)){
                        waterDeposit = waterDeposit*code.getQuota();
                    }else{
                        Double uesdMoney = LandSeaUtil.get2Double(waterDeposit - authWMoney);// 此次最多允许使用的优惠金额
                        Double crtAuthMoney = code.getQuota();// 此次优惠金额
                        if (authWMoney.compareTo(waterDeposit) < 0)
                        {// 如果优惠金额<费项金额 才允许使用授权码
                            Double realAuthMoney = 0.0;
                            if (crtAuthMoney.compareTo(uesdMoney) >= 0)
                            {// 如果当前优惠金额大于等于费项金额允许使用此次最大优惠金额
                                realAuthMoney = uesdMoney;
                                code.setQuota(realAuthMoney);
                            } else{
                                realAuthMoney = crtAuthMoney;
                            }
                            waterDeposit = waterDeposit-realAuthMoney;
                        }
                    }
                }
            }
        }

        //全额付，则付租期个月份
        if(PaymentModelCodeEnum.PAMO7 == PaymentModelCodeEnum.getPaymentModelCodeEnum(objCts.getPaymentMode())){
            objCts.setPayM(month);
        }else{
            objCts.setPayM(PaymentModelCodeEnum.getPaymentModelCodeEnum(objCts.getPaymentMode()).getPayMonth());
        }
        priceHourse =  LandSeaUtil.getIntDouble(priceHourse);
        objCts.setDepositM(depositBase);
        objCts.setSalePrice(priceHourse);//月租金
        objCts.setDeposit(LandSeaUtil.getIntDouble(depositPrice)); // 押金
        Double totalPrice = priceHourse * month;
        if(objCts.getLease().equals(LeaseCodeEnum.LEAS99.getCode())){
            Double dayOfMonth =Double.valueOf(configurationService.getStringValue(ConfigurationService.SYS_MONTHLY_AVA_DAYS));
            Double dayPrice = priceHourse/dayOfMonth*objCts.getLeaseD();
            totalPrice = totalPrice+dayPrice;
        }
        objCts.setTotalPrice(LandSeaUtil.getIntDouble(totalPrice));
        objCts.setPropertyFee(LandSeaUtil.getIntDouble(propertyFee));//服务费
        objCts.setWaterDeposit(LandSeaUtil.getIntDouble(waterDeposit));//水费押金
    }

    private Integer checkUserCellPhone(CreateOffLineContractsReq req)
            throws BusinessException {
        // 判断是否存在登录账号
        User pUser = new User();
        pUser.setId(req.getUserId());
        pUser.setLoginId(req.getCellPhone());
        User existUser = userService.itExistUser(pUser);

        UserDTO userDTO = new UserDTO();
        userDTO.setId(req.getUserId());

        userDTO.setLoginId(req.getCellPhone());
        CustomerDTO customerDTO = new CustomerDTO();
        customerDTO.setUserId(req.getUserId());
        customerDTO.setName(req.getCertificatesName());
        customerDTO.setPhone(req.getCellPhone());
        customerDTO.setGender(req.getGender());
        customerDTO.setCertificatesType(req.getCertificatesType());
        customerDTO.setCertificatesNo(req.getCertificatesId());
        customerDTO.setCertificatesAddress(req.getCertificatesAddress());
        userDTO.setCustomerDTO(customerDTO);
        if (existUser != null) {
            userDTO.setId(existUser.getId());
            userService.update(userDTO);
        } else {
            userDTO.setPassword(SysUtil.MD5Digest(userDTO.getLoginId().substring(userDTO.getLoginId().length() - 6)));
            Integer userId = userService.insert(userDTO);
            userDTO.setId(userId);

            // send message to notify the user about account info added by Daniel on 20170704
            try {
                String phone = userDTO.getLoginId();
                String name = customerDTO.getName();
                String pwd = userDTO.getLoginId().substring(userDTO.getLoginId().length() - 6);
                String gender = "";
                Code code = codeService.getCode(customerDTO.getGender());
                if (code != null) {
                    //gender = code.getCodeDescTr(); 注释掉短信中的女士或先生
                    gender = "";
                }
                // 尊敬的${name}，您的会员号是：${account}， 密码是${pwd}，谢谢。
                String params = " {'name':'" + name + gender + "','account':'" + phone + "','pwd':'" + pwd + "'}";
                String signName = configurationService.getStringValue(ConfigurationService.SEND_MSG_SIGN_NAME);
                SMSUtil.sendSms(sendMsgConfiguration.getAutoCreateAccountCode(), phone, params,signName);
            } catch (Exception e) {
                LOG.error("checkUserCellPhone error", e);
            }
        }

        return userDTO.getId();
    }

    @Override
    public Object get(Integer integer)
            throws BusinessException {

        return null;
    }

    @Override
    public void update(Object o)
            throws BusinessException {
        CreateOffLineContractsReq req = (CreateOffLineContractsReq) o;
        Integer systemId = updateCheck(req);

        validateForUpdate(o);
        // 修改用户信息
        checkUpdateUserCellPhone(req);

        RoomDetailReq aprt = roomService.searchRoomInfo(req.getRoomId());
        calculationMonthRent(aprt, req, null);
        Contract contract = UpdateOffLineContractsReq.convertDTOtoContract(req);
        contract.setSalePrice(req.getSalePrice());
        contract.setProjectId(aprt.getPrjId());
        contract.setDiscount(req.getDiscount());
        contract.setOriginalPrice(req.getPrice());
        contract.setTotalMoney(req.getTotalPrice());
        contract.setDeposit(req.getDeposit());
        contract.setPropertyFee(BigDecimal.valueOf(aprt.getPropertyFee()).doubleValue());
        contract.updateCommonInfo(systemId);
        contractWriteMapper.updateByPrimaryKeySelective(contract);

        // 修改紧急联系人
        if (req.getUrgentDTO() != null) {
            Urgent urgent = UrgentDTO.fromDTOtoUrgent(req.getUrgentDTO());
            urgent.updateCommonInfo(systemId);
            List<UrgentDTO> urgents =
                    urgentReadMapper.queryDetailByContractId(contract.getId(), UserTypeEnum.ROOMMATE.getCode());
            if (urgents == null || urgents.size() == 0) {
                urgentWriteMapper.insertSelective(urgent);
            } else {
                UrgentDTO userDTO = urgents.get(0);
                urgent.setId(userDTO.getId());
                urgentWriteMapper.updateByPrimaryKeySelective(urgent);
            }
        }

        // 重新生成pdf
        // 生成pdf
        try {
            contractService.createPdf(req.getContractId());
        } catch (Exception e) {
            LOG.info("重新生成pdf异常", e);
        }
    }

    @Override
    public void delete(String s)
            throws BusinessException {

    }

    private void checkUpdateUserCellPhone(CreateOffLineContractsReq req)
            throws BusinessException {

        User user = userService.get(req.getUserId());
        if (user == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_CUSTOMER_ISNULL);
        }
        UserDTO userDTO = new UserDTO();
        userDTO.setId(req.getUserId());
        userDTO.setLoginId(req.getCellPhone());
        CustomerDTO customerDTO = new CustomerDTO();
        customerDTO.setName(req.getCertificatesName());
        customerDTO.setPhone(req.getCellPhone());
        customerDTO.setGender(req.getGender());
        customerDTO.setCertificatesType(req.getCertificatesType());
        customerDTO.setCertificatesNo(req.getCertificatesId());
        customerDTO.setCertificatesAddress(req.getCertificatesAddress());
        userDTO.setCustomerDTO(customerDTO);
        userService.update(userDTO);
    }

    @Override
    public List<?> query(QueryUtil queryUtil) {
        return null;
    }

    @Override
    public Boolean validate(Object o)
            throws BusinessException {
        return null;
    }

    @Override
    public Boolean validateForInsert(Object o)
            throws BusinessException {

        CreateOffLineContractsReq req = (CreateOffLineContractsReq) o;
        if (req.getUserId() == null ) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_USERID_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCertificatesName())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_NAME_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCertificatesId())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_IDNO_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCertificatesType())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_IDTYPE_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCertificatesAddress())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ADDRESS_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCellPhone())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_CELLPHONE_ISNULL);
        }

        if (req.getProjectId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECTID_ISNULL);
        }

        if (req.getRoomId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOMID_ISNULL);
        }

        if (StringUtils.isEmpty(req.getPaymentMode())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PAYMENTMODE_ISNULL);
        }

        if (StringUtils.isEmpty(req.getLease())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_LEASE_ISNULL);
        }

        if (req.getInDate() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_INDATE_ISNULL);
        }

        if (req.getOutDate() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_OUTDATE_ISNULL);
        }
        if (StringUtils.isEmpty(req.getSource())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_OUTDATE_ISNULL);
        }
        //如果租期为其他 leaseM   leaseD 不能为空
        if(req.getLease().equals(LeaseCodeEnum.LEAS99.getCode())){
            if(req.getLeaseM()==null || req.getLeaseD()==null){
                throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_LEASEMD_INDATE_INVALID);
            }
        }
        /*if (!DateUtil.getInstence().compareNow(DateUtil.getInstence().convertDate(req.getInDate()))) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_INDATE_INVALID);
        }*/
        return true;
    }

    @Override
    public Boolean validateForUpdate(Object o)
            throws BusinessException {
        CreateOffLineContractsReq req = (CreateOffLineContractsReq) o;

        if (req.getContractId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CONTRACTID_ISNULL);
        }
        if (req.getUserId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_USERID_ISNULL);
        }
     /*   if (StringUtils.isEmpty(req.getCertificatesName())) {
        }
        if (StringUtils.isEmpty(req.getCertificatesId())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_IDNO_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCertificatesType())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_IDTYPE_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCertificatesAddress())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ADDRESS_ISNULL);
        }
        if (StringUtils.isEmpty(req.getCellPhone())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_CELLPHONE_ISNULL);
        }*/
        if (req.getProjectId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PROJECTID_ISNULL);
        }
        if (req.getRoomId() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_ROOMID_ISNULL);
        }
        if (StringUtils.isEmpty(req.getPaymentMode())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_PAYMENTMODE_ISNULL);
        }

        if (StringUtils.isEmpty(req.getLease())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_LEASE_ISNULL);
        }

        if (req.getInDate() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_INDATE_ISNULL);
        }

        if (req.getOutDate() == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_OUTDATE_ISNULL);
        }
        if (StringUtils.isEmpty(req.getSource())) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_CREATE_OUTDATE_ISNULL);
        }
        return null;
    }

    @Override
    public Boolean validateForDelete(Object o)
            throws BusinessException {
        return null;
    }

    @Override
    public void updateContractBaseInfo(Object obj)
            throws LandseaBusinessException {
        CreateContractUrgentReq objCts = (CreateContractUrgentReq) obj;
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        Contract contract = contractReadMapper.selectByPrimaryKey(objCts.getContractId());
        if (contract == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CONTRACT_ISNULL);
        }
        validBaseInfo(objCts);
        for (ContractUser user : objCts.getContractUsers()) {
            // 如果是个人信息，则修改合同个人信息
          /*  if (user.getUserRelation().equals(UserTypeEnum.MYSELF.getCode())) {
                contract.setCountry(user.getCountry());
                contract.setGender(user.getGender());
                contract.updateCommonInfo(systemId);
                contractWriteMapper.updateByPrimaryKeySelective(contract);
            }*/
            // 添加或修改室友信息
            if (user.getUserRelation().equals(UserTypeEnum.ROOMMATE.getCode())) {
                Urgent urgent = ContractUser.fromattoUrgent(user);
                urgent.updateCommonInfo(systemId);
                // 如果编号为空则为新增，否则为修改
                if (urgent.getId() != null && urgent.getId() != 0) {
                    urgentWriteMapper.updateByPrimaryKeySelective(urgent);
                } else {
                    urgentWriteMapper.insertSelective(urgent);
                }
            }
        }
    }

    private void validBaseInfo(CreateContractUrgentReq objCts)
            throws LandseaBusinessException {
        List<ContractUser> contractUsers = objCts.getContractUsers();
        // 室友最多为2个
        int roommate = 0;
        if (contractUsers != null) {
            for (ContractUser user : contractUsers) {
                if (user.getUserRelation().equals(UserTypeEnum.ROOMMATE.getCode())) {
                    roommate++;
                }
                if (StringUtils.isEmpty(user.getUserName())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_USERNAME_ISNULL);
                }
                if (StringUtils.isEmpty(user.getGender())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_GENDER_ISNULL);
                }
                if (StringUtils.isEmpty(user.getCountry())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_GENDER_ISNULL);
                }
                if (StringUtils.isEmpty(user.getUserPhone())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_PHONE_ISNULL);
                }
                if (StringUtils.isEmpty(user.getCertificatesType())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_IDTYPE_ISNULL);
                }
                if (StringUtils.isEmpty(user.getCertificatesId())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_IDNO_ISNULL);
                }
                if (StringUtils.isEmpty(user.getAddress())) {
                    throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_ADDRESS_ISNULL);
                }
            }
            if (roommate > 2) {
                throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_ROOMMATES_ISNULL);
            }
        } else {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_USERS_ISNULL);
        }
    }

    @Override
    public void deleteContractRoommate(Integer id)
            throws LandseaBusinessException {
        if (id == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_BASEINFO_ROOMMATEID_ISNULL);
        }
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        urgentWriteMapper.deleteUrgent(id);
    }


    @Override
    public void updateAuthCode(Object object) throws LandseaException, BusinessException, Exception {
        CreateOffLineContractsReq objCts = (CreateOffLineContractsReq) object;

        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        Contract oldContract = contractReadMapper.selectByPrimaryKey(objCts.getContractId());
        if (oldContract == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CONTRACT_ISNULL);
        }
        if (oldContract.getIsChapter()) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CHAPTER);
        }
         //查看授权码是否没有更改
        HashMap map= new HashMap();
        map.put("mainId",oldContract.getId());
        map.put("mainType",LandeaConstants.QueryUesdCodeType.CONTRACT);
        List<QueryCouponUesdDTO> qcu = couponUsedService.querypPersonalCouponList(map);
        CustomerCardDTO cardDTO = customerCardReadMapper.queryCardInfo(map);
        List<UsedAuthCode> addCpList = objCts.getAuthCodes();
        boolean changeFlag = checkChangeFlag(qcu, addCpList);
        boolean changeCard = false;
        if(!cardDTO.getCardAccount().equals(objCts.getCardAccount())
                || !cardDTO.getCardUserName().equals(objCts.getCardUserName())
                || !cardDTO.getCellPhone().equals(objCts.getCardCellPhone())
                || !cardDTO.getBankName().equals(objCts.getBankName())
                || !cardDTO.getBankBrname().equals(objCts.getBankBrname())
                || !cardDTO.getCardNo().equals(objCts.getCardNo())){
            changeCard = true;
            //修改银行卡信息
            CustomerCard cardInfo = CreateOffLineContractsReq.convertDTOtoCustomerCard(objCts);
            cardDTO.setSourceId(objCts.getContractId());
            customerCardService.updateCustomerCard(cardDTO);
        }
        if(!changeFlag){
            //校验授权码
            couponUsedService.checkUesdAuthCode(LandeaConstants.QueryUesdCodeType.CONTRACT,oldContract.getUserId(),objCts.getAuthCodes());
            RoomDetailReq aprt = roomService.searchRoomInfo(objCts.getRoomId());
            boolean changeCtrc = oldContract.getSourceRentType()!=null && oldContract.getSourceRentType().equals(LandeaConstants.ReRentType.CHANGE);
            //取原始合同
            Contract contractA = null;
            //如果是转租
            if(changeCtrc){
                contractA = contractReadMapper.selectByPrimaryKey(oldContract.getOriginalCId());
                aprt.setRent(contractA.getSalePrice());
                aprt.setPropertyFee(contractA.getPropertyFee());
                aprt.getProject().setDepositWater(contractA.getWaterDeposit());
                aprt.setOprType(LandeaConstants.ReRentType.CHANGE);
            }
            calculationMonthRent(aprt, objCts, null);
            // 修改合同
            Contract ctc = CreateOffLineContractsReq.convertDTOtoContract(objCts);
            ctc.setId(objCts.getContractId());
            if(changeCtrc){
                ctc.setOriginalPrice(contractA.getSalePrice());//房间原价=B合同优惠后月租
                ctc.setOriginalWaterDeposit(contractA.getWaterDeposit());//水费押金
            }
            ctc.updateCommonInfo(systemId);
            contractWriteMapper.updateByPrimaryKeySelective(ctc);
            // 先删除之前用过的授权码
            couponUsedService.removeCouponUesd(oldContract.getId(), LandeaConstants.QueryUesdCodeType.CONTRACT);
            //删除首付款
            Bill parBill = billService.queryFirstBill(objCts.getContractId());
            billService.deleteBill(parBill.getId());
            // 删除首期的独立账单,根据合同ID、账单ID、账单类型
            Map<String,Object> paramMap = new HashMap<String,Object>();
            paramMap.put("contractId", objCts.getContractId());
            paramMap.put("billId", parBill.getId());
            billIndependentService.removeFirstBillBalance(paramMap);
            //重新生成首付款
            billService.createFirstBill(objCts.getContractId(),objCts.getAuthCodes());
        }
        //判断是否修改了银行卡信息
        if(!changeFlag || changeCard){
            // 生成pdf
            try {
                contractService.createPdf(objCts.getContractId());
            } catch (Exception e) {
                LOG.info("重新生成pdf异常", e);
            }
        }
    }

    private boolean checkChangeFlag(List<QueryCouponUesdDTO> qcu, List<UsedAuthCode> addCpList) {
        Boolean changeFlag = true;
        if(addCpList==null){
            addCpList = new ArrayList<>();
        }
        if(qcu.size()!=addCpList.size()){
            changeFlag = false;
        }else{
            class CouponInfo{
                private Integer couponId;
                private Double quota;
                public Integer getCouponId() {
                    return couponId;
                }
                public void setCouponId(Integer couponId) {
                    this.couponId = couponId;
                }
                public Double getQuota() {
                    return quota;
                }
                public void setQuota(Double quota) {
                    this.quota = quota;
                }
                public CouponInfo(Integer couponId, Double quota) {
                    this.couponId = couponId;
                    this.quota = quota;
                }
                public boolean equals(Object o){
                    if (this==o) return true;
                    if (!(o instanceof CouponInfo)) return false;
                    final CouponInfo other = (CouponInfo)o;
                    if(this.quota.compareTo(other.getQuota())==0 && this.couponId.equals(other.getCouponId()))
                        return true;
                    else
                        return false;
                }
            }
            List<CouponInfo> uesdIds = new ArrayList<>();
            List<CouponInfo> addIds = new ArrayList<>();
            if(qcu.size()>0){
                qcu.forEach(e->uesdIds.add(new CouponInfo(e.getId(),e.getQuota())));
            }
            if(addCpList.size()>0){
                addCpList.forEach(e->addIds.add(new CouponInfo(e.getId(),e.getQuota())));
            }
            List<CouponInfo> list1 = uesdIds.stream()
                    .sorted(Comparator.comparing(CouponInfo::getCouponId).reversed()).collect(Collectors.toList());
            List<CouponInfo> list2 = addIds.stream()
                    .sorted(Comparator.comparing(CouponInfo::getCouponId).reversed()).collect(Collectors.toList());
            if(!list1.equals(list2)){
                changeFlag = false;
            }
        }
        return changeFlag;
    }

    private Integer updateCheck(CreateOffLineContractsReq req) throws BusinessException {
        Integer systemId = SecurityUtils.getCurrentLogin().getUserId();
        if (systemId == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.TOKEN_IS_NULL);
        }
        Contract oldContract = contractReadMapper.selectByPrimaryKey(req.getContractId());
        if (oldContract == null) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CONTRACT_ISNULL);
        }
        if (oldContract.getIsChapter()) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_CHAPTER);
        }
        // 判断是否已付款
        Boolean isPayed = billService.getBillStatusForId(req.getContractId());
        if (isPayed) {
            throw new LandseaBusinessException(LandseaErrorMessageEnum.CONTRACT_OFFLINE_UPDATE_ISPAYED);
        }
        return systemId;
    }
}
